package cn.jinzhu.hystrix.service;

import cn.jinzhu.entity.User;
import com.netflix.discovery.util.StringUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import com.netflix.hystrix.contrib.javanica.command.AsyncResult;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Future;

//提供断路器的配置
@Service
public class HelloService {

    @Resource
    RestTemplate restTemplate;
/*
* 在这个方法中我们将发起一个远程调用，去提供者hello获取，但是会失败，这个时候就要触发短路器的 功能
*为了失败要添加@HystrixCommand(fallbackMethod = "error")，也就是下面方法失败了就重新给error方法，名称要一样，也就是服务降级
*
* *
///断路器的一种功能服务降级，这个方法失败去找下一个方法，该方法名称要对应这个,还有参数也要一样
而且替代的方法返回值要和失败的方法返回值一致，也就是等下失败回去找一个叫做error的返回值为string的方法
 *///ignoreExceptions就是出现了这个里面的这个异常就不服务降级，直接抛出
   @HystrixCommand(fallbackMethod = "error",ignoreExceptions = ArithmeticException.class)//请求失败的回调   降级有二种方式，一种继承一种注解，异常处理也是跟他们一样。目的是为他们二个提供服务
    public String hello(){
       int i = 1 / 0;//出现异常，里面降级进入到error
       return  restTemplate.getForObject("http://provider/hello",String.class);
    }
    @HystrixCommand(fallbackMethod = "error1")
    public String error(Throwable throwable){//处理降级获取的异常，用大异常获取Throwable,以为降级控制台不会报错
        return  "error"+throwable.getMessage();
    }
    @HystrixCommand(fallbackMethod = "error1")
    public String error1(){
        return  "error1";
    }
    //以注解的方式实现异步调用  也叫做号外 ,要new异步,注意别导错包
    @HystrixCommand(fallbackMethod = "error")
    public Future<String> hello1(){

       return new AsyncResult(){//异步调用

           @Override
           public Object invoke() {
               return restTemplate.getForObject("http://provider/hello",String.class);
           }
       };
    }

    @HystrixCommand(fallbackMethod = "error2")
    @CacheResult //hystrix断路器开启缓存，key就是方法参数，value就是返回值，只要参数不改，直接去缓存获取,参数有多个就合成一个key
    public String hello2(String name){
    return restTemplate.getForObject("http://provider/hello1?name={name}",String.class,name);//存储方式{name}等于后面那个name
    }

    public String error2(String name,Throwable throwable){
       return  "哈哈error2"+name+throwable.getMessage();
    }

    @HystrixCommand(fallbackMethod = "error2")
    @CacheRemove(commandKey = "hello2") //hystrix断路器开启缓存，删除缓存就是删除那个方法
    public String hello3(String name){
       return  null;
    }


    @HystrixCommand
    public List<User> users(List<Integer> ids){ //继承的方式实现请求合并
       User[] users= restTemplate.getForObject("http://provider/userById/{ids}",User[].class,
                StringUtils.join(ids,","));//字符串数组要用，分割， StringUtils.join 进行分割
       return Arrays.asList(users);
    }
    //注解非常简单 ，只需要指定批处理的方法就行users就是上面那个方法,上面那个方法要标@HystrixCommand
    @HystrixCollapser(batchMethod = "users",collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds", value ="200" )})//请求合并注解，
     public Future<User> getUserById(Integer id){
       return  null;
     }

}
